package com.ctrip.framework.apollo.openapi.client.service;

import com.ctrip.framework.apollo.openapi.client.exception.ApolloOpenApiException;
import com.ctrip.framework.apollo.openapi.client.url.OpenApiPathBuilder;
import com.google.common.base.Preconditions;
import com.google.common.base.Strings;
import com.google.gson.Gson;
import org.apache.http.HttpResponse;
import org.apache.http.StatusLine;
import org.apache.http.client.methods.*;
import org.apache.http.entity.ContentType;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.util.EntityUtils;

import java.io.IOException;

abstract class AbstractOpenApiService {
    private final String baseUrl;

    protected final CloseableHttpClient client;
    protected final Gson gson;

    AbstractOpenApiService(CloseableHttpClient client, String baseUrl, Gson gson) {
        this.client = client;
        this.baseUrl = baseUrl;
        this.gson = gson;
    }

    protected CloseableHttpResponse get(OpenApiPathBuilder path) throws IOException {
        HttpGet get = new HttpGet(path.buildPath(baseUrl));
        return execute(get);
    }

    protected CloseableHttpResponse post(OpenApiPathBuilder path, Object entity) throws IOException {
        HttpPost post = new HttpPost(path.buildPath(baseUrl));
        return execute(post, entity);
    }

    protected CloseableHttpResponse put(OpenApiPathBuilder path, Object entity) throws IOException {
        HttpPut put = new HttpPut(path.buildPath(baseUrl));
        return execute(put, entity);
    }

    protected CloseableHttpResponse delete(OpenApiPathBuilder path) throws IOException {
        HttpDelete delete = new HttpDelete(path.buildPath(baseUrl));
        return execute(delete);
    }

    private CloseableHttpResponse execute(HttpEntityEnclosingRequestBase requestBase, Object entity) throws IOException {
        requestBase.setEntity(new StringEntity(gson.toJson(entity), ContentType.APPLICATION_JSON));
        return execute(requestBase);
    }

    private CloseableHttpResponse execute(HttpUriRequest request) throws IOException {
        CloseableHttpResponse response = client.execute(request);
        checkHttpResponseStatus(response);
        return response;
    }

    private void checkHttpResponseStatus(HttpResponse response) {
        if (response.getStatusLine().getStatusCode() == 200) {
            return;
        }

        StatusLine status = response.getStatusLine();
        String message = "";
        try {
            message = EntityUtils.toString(response.getEntity());
        } catch (IOException e) {
            // ignore
        }

        throw new ApolloOpenApiException(status.getStatusCode(), status.getReasonPhrase(), message);
    }

    protected void checkNotEmpty(String value, String name) {
        Preconditions.checkArgument(!Strings.isNullOrEmpty(value), name + " should not be null or empty");
    }
}
